package com.earthea.api.lock;

import com.google.common.base.Preconditions;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.ThreadUtils;

import java.time.Duration;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public abstract class AbstractLock implements Lock {
    protected final String lockId;

    protected final long timeout;

    public AbstractLock(String lockId, long timeout) {
        Preconditions.checkArgument(timeout > 0, "timeout must be greater than 0");
        Preconditions.checkArgument(StringUtils.isNotBlank(lockId), "lockId must not be blank");
        this.lockId = lockId;
        this.timeout = timeout;
    }

    @Override
    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        Preconditions.checkArgument(time > 0, "time must be greater than 0");
        Preconditions.checkNotNull(unit, "unit must not be null");
        long timeout = unit.toMillis(time);
        long now = System.currentTimeMillis();
        while (System.currentTimeMillis() - now <= timeout) {
            if (tryLock()) {
                return true;
            }
            ThreadUtils.sleepQuietly(Duration.ofMillis(50));
        }
        return false;
    }

    @Override
    public void lockInterruptibly() throws InterruptedException {
        tryLock(Long.MAX_VALUE, TimeUnit.SECONDS);
    }

    @Override
    public void lock() {
        try {
            lockInterruptibly();
        } catch (InterruptedException e) {
            unlock();
        }
    }

    @Override
    public Condition newCondition() {
        throw new UnsupportedOperationException("newCondition not implemented");
    }
}
